#include "jasynchronization.h"

namespace QTE
{

class Q_DECL_HIDDEN JAsynchronizationPrivate : public QObject
{
public:
	using QObject::QObject;

public:
	void setThreadPool(QThreadPool *pool);

public:
	QThreadPool *m_pool = QThreadPool::globalInstance();
	std::atomic_bool isCallBackInEventLoop {true};
};

class Q_DECL_HIDDEN WaitDeleteThread : public QThread
{
public:
	explicit WaitDeleteThread(QThreadPool *pool) :
		m_pool(pool) {}

protected:
	void run() override
	{
		m_pool->waitForDone();
		delete m_pool;
	}

private:
	QThreadPool *m_pool;
};

void JAsynchronizationPrivate::setThreadPool(QThreadPool *pool)
{
	if( m_pool == pool )
		return ;

	if( m_pool and m_pool != QThreadPool::globalInstance() )
	{
		auto thread = new WaitDeleteThread(m_pool);
		QObject::connect(thread, &WaitDeleteThread::finished, thread, &WaitDeleteThread::deleteLater);
		thread->start(QThread::LowestPriority);
	}

	m_pool = pool;
	if( m_pool != QThreadPool::globalInstance() )
		m_pool->setParent(this);
}

/*----------------------------------------------------------------------------------------*/

JAsynchronization::JAsynchronization(QObject *parent) :
	QObject(parent),
	d_ptr(new JAsynchronizationPrivate(this))
{

}

JAsynchronization::JAsynchronization(bool isCallBackInEventLoop, QObject *parent) :
	JAsynchronization(parent)
{
	d_ptr->isCallBackInEventLoop = isCallBackInEventLoop;
}

JAsynchronization::JAsynchronization(QThreadPool *pool, QObject *parent) :
	JAsynchronization(parent)
{
	setThreadPool(pool);
}

JAsynchronization::JAsynchronization(QThreadPool *pool, bool isCallBackInEventLoop, QObject *parent) :
	JAsynchronization(isCallBackInEventLoop, parent)
{
	setThreadPool(pool);
}

JAsynchronization::~JAsynchronization()
{

}

JAsynchronization &JAsynchronization::globalInstance()
{
	static JAsynchronization jc;
	return jc;
}

bool JAsynchronization::waitForDone(int msecs)
{
	return d_ptr->m_pool->waitForDone(msecs);
}

void JAsynchronization::setCallBackInEventLoop(bool flag)
{
	d_ptr->isCallBackInEventLoop = flag;
}

bool JAsynchronization::isCallBackInEventLoop() const
{
	return d_ptr->isCallBackInEventLoop;
}

void JAsynchronization::setThreadPool(QThreadPool *pool)
{
	d_ptr->setThreadPool(pool);
}

QThreadPool *JAsynchronization::threadPool() const
{
	return d_ptr->m_pool;
}

void TaskCallBack::customEvent(QEvent *event)
{
	QObject::customEvent(event);
	auto REvent = J_DCT(JRunnableCallBackEvent*, event);

	if( REvent )
	{
		if( REvent->qobj )
		{
			if( not REvent->qobj->isNull() )
				REvent->callBack();
			delete REvent->qobj;
		}
		else
			REvent->callBack();
	}
	deleteLater();
}

} //namespace QTE
